from random import randint
from django.shortcuts import render
from django.views import View
from django.core.cache import cache
from django.http import HttpResponse
from spider.main import GoodsSpider
from backend.models import User,DailyStatistics,Comment
from backend.models import Admin,User
from frontend.models import Goods, KeyWord, UserAndGoods
from django.http import QueryDict
from django.shortcuts import redirect
import json
import datetime,time,os
import hashlib   
from PriceCompare import settings
from backend.imageCode import getImgCode
from backend.utils import DailyStatisticsAdd
from backend.utils import updateCookies
from backend.utils import strmd5
from backend.utils import sendMessage
from urllib import parse
from alipay import AliPay, DCAliPay, ISVAliPay
from alipay.utils import AliPayConfig
from django.http import JsonResponse
from backend.models import Payment,OrderInfo
# Create your views here.
class UserView(View):
    """
    用户表的操作
    """
    def get(self,request):
        pass

    def post(self,request):
        """
        创建用户
        """
        email = request.POST.get('email',None)
        phone = request.POST.get('phone',None)
        password = request.POST.get('password',None)
        name = request.POST.get('name',None)
        qq = request.POST.get('qq',None)
        print(request.POST)
        image = '/randomImage/?index='+ str(randint(1,10))
        # md5 加密密码
        password=strmd5(password)
        print(password)
        try:
            if User.objects.filter(phone=phone) :
                return HttpResponse(json.dumps({'response':False,"content":'该手机号码已注册，请勿重复注册'}))
            User.objects.create(
                email=email,
                phone=phone,
                name=name,
                password=password,
                qq=qq,
                score='100',
                image=image,
                last=datetime.datetime.now()
            )
            # 统计每日新增
            DailyStatisticsAdd('useradd')
            return HttpResponse(json.dumps({'response':True,"content":'注册成功'}))
        except Exception as e:
            print(e)
            return HttpResponse(json.dumps({'response':False,"content":'注册失败，请检查信息'}))
    
    def put(self,request):
        """
        修改用户信息
        """
        PUT = QueryDict(request.body)
        name = PUT.get('name',None)
        email = PUT.get('email',None)
        qq = PUT.get('qq',None)
        print(name,email,qq)
        cookie = request.COOKIES
        login = cookie.get('login',None)
        phone = cookie.get('phone',None)
        if not login : return redirect('/static/login.html')
        try:
            user = User.objects.get(phone=phone)
            if name: user.name = name 
            if email: user.email=email
            if qq: user.qq=qq
            user.save()
            # 更新cookie
            resp = HttpResponse(json.dumps({'response':True}))
            resp = updateCookies(resp,name=name,email=email,qq=qq)
            return resp
        except Exception as e:
            print(e)
            return HttpResponse(json.dumps({'response':False}))

        
def alterpassword(request):
    """
    修改密码
    方式:POST
    """
    POST = request.POST
    cookie = request.COOKIES
    oldpwd = POST.get('oldpwd',None)
    newpwd = POST.get('newpwd',None)
    login = cookie.get('login',None)
    phone = cookie.get('phone',None)
    print(oldpwd,newpwd,login,phone)
    if not oldpwd or not newpwd : return
    # md5 加密密码
    if oldpwd : oldpwd = strmd5(oldpwd)
    if newpwd : newpwd = strmd5(newpwd)
    if not login : return redirect('/static/login.html')
    if User.objects.filter(phone=phone):
        user = User.objects.get(phone=phone)
        if oldpwd == user.password:
            user.password = newpwd
            user.save()
            return HttpResponse(json.dumps({'response':True,'msg':'密码修改成功'}))
        else:
            return HttpResponse(json.dumps({'response':False,'msg':'旧密码错误'}))
        
def validcode(request):
    """
    验证码
    方式:GET
    参数:
    - type : email邮箱验证，phone手机验证
    """
    cookie = request.COOKIES
    type_ = request.GET.get('type',None)
    email = cookie.get('email',None)
    name = cookie.get('name',None)
    print(type_,email)
    if not type_ or not email : return
    code = "".join([str(randint(0,9)) for i in range(4)])
    err = ''
    if type == 'phone':
        return HttpResponse(json.dumps({'code':code}))
    else:
        # content = f"""
        # <div>
        # <img src='https://hedu-typora.oss-cn-beijing.aliyuncs.com/python/FD7C6347DE9038C76A52E552E93F7089.jpg' style="width:300px;height=300px" alt='请查收邮件'>
        # </div>
        # <div>
        # <br><br>
        # <p>您正在使用修改密码功能,该验证码仅用于身份验证,请勿泄露给其他人</p>
        # <p><h5>验证码:{code}</h5></p>
        # </div>
        # """
        with open(os.path.join(settings.BASE_DIR,'static_files','mail_template.html'),'rt',encoding='utf-8') as f:
            content = f.read()
            content=content.replace('{user}',name)
            content=content.replace('{siteUrl}','127.0.0.1:8000/')
            content=content.replace('{codeText}',code)
        try:
            sendMessage(content,email,"Price比价平台邮件验证码",conten_type='html',name=name)
        except Exception as e:
            print(e)
            code = ''
            err = '请在基本资料中修改正确的邮箱地址'
        return HttpResponse(json.dumps({'code':code,'err':err}))



def imageCodeManage(request):
    """
    图片验证码
    方式:GET
    描述:图片直接返回，验证码值写入cookie
    """
    resp = getImgCode()
    code = resp['code']
    img = resp['image']
    contentType=resp['Content-Type']
    resp = HttpResponse(img,content_type=contentType)
    resp.set_cookie('login_code',code,max_age=60*5)
    return resp


def login(request):
    """
    处理登录
    方式:POST
    """
    password = request.POST.get('password',None)
    username = request.POST.get('username',None) # username为用户phone字段
    print(username,password)
    if password and username :
        # md5 加密密码
        password=strmd5(password)
        # 管理员账号判断
        if Admin.objects.filter(username=username):
            admin = Admin.objects.get(username=username)
            if admin.password == password:
                #权限 0 high,1 low
                resp = HttpResponse(json.dumps({'response':True,"content":'登录成功,你的身份为管理员'}))
                resp.set_cookie('login','admin',path='/',max_age=15*24*3600)  # 用来判断是否登录
                resp.set_cookie('name',admin.username,path='/',max_age=15*24*3600)
                resp.set_cookie('authority',admin.authority,path='/',max_age=15*24*3600)
                return resp
            else:
                return HttpResponse(json.dumps({'response':False,"content":'密码错误'}))
        # 用户账号判断
        elif User.objects.filter(phone=username):
            user = User.objects.get(phone=username)
            if user.password == password :
                # 统计每日新增
                DailyStatisticsAdd('login')
                # 更新最后登陆时间
                user.last = datetime.datetime.now()
                user.save()
                # 把用户的具体信息写入cookie
                resp = HttpResponse(json.dumps({'response':True,"content":'登录成功'}))
                resp.set_cookie('login','user',path='/',max_age=15*24*3600)  # 用来判断是否登录
                resp.set_cookie('phone',user.phone,path='/',max_age=15*24*3600)
                resp.set_cookie('email',user.email,path='/',max_age=15*24*3600)
                resp.set_cookie('name',user.name,path='/',max_age=15*24*3600)
                resp.set_cookie('score',user.score,path='/',max_age=15*24*3600)
                resp.set_cookie('image',user.image,path='/',max_age=15*24*3600)
                resp.set_cookie('qq',user.qq,path='/',max_age=15*24*3600)
                resp.set_cookie('last',user.last,path='/',max_age=15*24*3600)
                return resp
            else:
                return HttpResponse(json.dumps({'response':False,"content":'密码错误'}))
        else:
            return HttpResponse(json.dumps({'response':False,"content":'用户名不存在'}))

def getUserHistory_or_Collection(request):
    """
    查询用户历史记录或收藏记录
    方式:GET
    """
    cookie = request.COOKIES
    GET = request.GET
    type_ = GET.get('type','history')
    page = int(GET.get('page',1))
    limit = int(GET.get('limit',15))
    login = cookie.get('login',None)
    phone = cookie.get('phone',None)
    searchParam = GET.get('searchParams',None)
    # url = request.get_raw_uri()
    # print('url=',url)
    print(type_,page,limit,login,phone,searchParam)
    if not login : return redirect('/static/login.html')
    user = User.objects.get(phone=phone)
    start = (page-1)*limit
    end = page*limit
    # 获取所有浏览/收藏记录
    records_all = user.userandgoods_set.filter(relation__contains='浏览' if type_ == 'history' else '收藏')
    # 根据搜索参数过滤
    if searchParam:
        formData = json.loads(parse.unquote(searchParam))
        name = formData.get('name',None)
        price = formData.get('price',None)
        dtime=formData.get('datetime',None)
        # 按时间
        if dtime:
            # print(dtime,dtime.split(' - '))
            time_st,time_end=dtime.split(' - ')
            time_st = datetime.datetime.strptime(time_st,'%Y-%m-%d')
            time_end = datetime.datetime.strptime(time_end,'%Y-%m-%d')
            records_all = records_all.filter(time__gte=time_st,time__lte=time_end)
        # 按名称
        if name: records_all = records_all.filter(goods__name__icontains=name)
        # 按价格
        if price: records_all = records_all.filter(goods__price__lte=float(price))
    # 处理为一页的大小
    records = records_all[start:end]
    formData={
        'code':0,
        'msg':'',
        'count':len(records_all),
        'data':[]
    }
    # 如果是历史记录，整理相关字段
    if type_ == 'history':
        for record in records:
            goods = record.goods
            formData['data'].append({
                'id':record.id,
                'name':goods.name,
                'price':goods.price,
                'datetime':record.time.strftime('%Y-%m-%d %H:%M:%S'),
                'mall':goods.mall,
                'store':goods.store,
                'link':goods.link,
                'collection':'是' if '收藏' in record.relation else '否'
            })
    # 如果是收藏
    else:
        for record in records:
            goods = record.goods
            formData['data'].append({
                'id':record.id,
                'name':goods.name,
                'price':goods.price,
                'datetime':record.time.strftime('%Y-%m-%d %H:%M:%S'),
                'mall':goods.mall,
                'store':goods.store,
                'link':goods.link
            })
    print(formData)
    return HttpResponse(json.dumps(formData))

def delUserHistory_or_Collection(request):
    """
    删除用户历史记录或收藏记录
    方式:POST
    """
    POST = request.POST
    print(POST)
    table_ids = POST.get('formID',None)
    table_ids = list(map(int,table_ids.split(',')))
    for id in table_ids:
        UserAndGoods.objects.get(id=id).delete()
    return HttpResponse(json.dumps({'code':0,'msg':'删除成功'}))

def getPriceTrend(request):
    import requests,json,time
    url = request.POST.get('url',None)
    print('url=',url)
    headers={'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.46'}
    resp = requests.get(url,headers=headers)
    dj = json.loads(resp.text)
    priceData = json.loads('['+dj['datePrice']+']')
    data = []
    for item in priceData:
        data.append([time.strftime("%Y-%m-%d", time.localtime(float(item[0]/1000))),item[1]])
    data = data[::7]
    print('data=',data)
    title = dj['spName']
    return HttpResponse(json.dumps({"title":title,"data":data}))

def StatisticsManage(request):
    """
    处理获取统计数据的请求
    field:
    - login:每日登录次数
    - search:每日搜索次数
    - comment:每日评论数
    - collection:每日收藏数
    - useradd:每日用户数
    - word_freq:词频
    - goodsComment:商品和评论数
    - goodsCollection:商品和收藏数
    - goodsGlance:商品和浏览数
    type: 无或normal为默认，add为累加
    style: line 折线图，bar 柱状图，pie 扇形图
    返回值格式:
    格式{'title_list':列表,'data_list':列表}
    """
    year = request.GET.get('year',None)
    month = request.GET.get('month',None) 
    day = request.GET.get('day',None)
    field = request.GET.get('field',None)
    type_ = request.GET.get('type',None) # 无或normal为默认，add为累加
    style = request.GET.get('style',None) # 无或normal为默认，add为累加

    if not field: raise Exception("获取统计数据未指定字段")
    print(year,month,day,field,type_,style)
    if field == 'word_freq':    
        style = style if style else 'pie' # 默认style为pie
        keywords = KeyWord.objects.all()
        if style =='bar':
            keywords = list(keywords)
            keywords.sort(key=lambda x:x.count,reverse=True)
            title_list = [key.keyword for key in keywords]
            data_list = [key.count for key in keywords]
        elif style == 'line':
            title_list = [key.keyword for key in keywords]
            data_list = [key.count for key in keywords]
        elif style == 'pie':
            title_list = [key.keyword for key in keywords]
            data_list = [{'value':key.count,'name':key.keyword} for key in keywords]
    elif field == 'goodsComment': # 商品评论
        style = style if style else 'pie' # 默认style为pie
        goods = Goods.objects.all()
        if style =='bar':
            goods = list(goods)
            goods.sort(key=lambda x:len(x.comment_set.all()),reverse=True)
            title_list = [key.name for key in goods]
            data_list = [len(key.comment_set.all()) for key in goods]
        elif style == 'line':
            title_list = [key.name for key in goods]
            data_list = [len(key.comment_set.all()) for key in goods]
        elif style == 'pie':
            title_list = [key.name for key in goods]
            data_list = [{'value':len(key.comment_set.all()),'name':key.name} for key in goods]
    elif field == 'goodsCollection': # 商品收藏
        style = style if style else 'pie' # 默认style为pie
        goods = Goods.objects.all()
        if style =='bar':
            goods = list(goods)
            goods.sort(key=lambda x:len(x.userandgoods_set.filter(relation__contains='关注')),reverse=True)
            title_list,data_list=[],[]
            for good in goods:
                data = len(good.userandgoods_set.filter(relation__contains='关注'))
                if data == 0 :break
                title_list.append(good.name)
                data_list.append(data)
                print(title_list,data_list)
        elif style == 'line':
            title_list = [key.name for key in goods]
            data_list = [len(key.userandgoods_set.filter(relation__contains='关注')) for key in goods]
        elif style == 'pie':
            goods = list(goods)
            goods.sort(key=lambda x:len(x.userandgoods_set.filter(relation__contains='关注')),reverse=True)
            title_list,data_list=[],[]
            for good in goods:
                data = len(good.userandgoods_set.filter(relation__contains='关注'))
                if data == 0 :break
                title_list.append(good.name)
                data_list.append({'value':data,'name':good.name})
    elif field == 'goodsGlance': # 商品浏览
        style = style if style else 'pie' # 默认style为pie
        goods = Goods.objects.all()
        if style =='bar':
            goods = list(goods)
            goods.sort(key=lambda x:len(x.userandgoods_set.filter(relation__contains='浏览')),reverse=True)
            title_list,data_list=[],[]
            for good in goods:
                data = len(good.userandgoods_set.filter(relation__contains='浏览'))
                if data == 0 :break
                title_list.append(good.name)
                data_list.append(data)
                print(title_list,data_list)
        elif style == 'line':
            title_list = [key.name for key in goods]
            data_list = [len(key.userandgoods_set.filter(relation__contains='浏览')) for key in goods]
        elif style == 'pie':
            goods = list(goods)
            goods.sort(key=lambda x:len(x.userandgoods_set.filter(relation__contains='浏览')),reverse=True)
            title_list,data_list=[],[]
            for good in goods:
                data = len(good.userandgoods_set.filter(relation__contains='浏览'))
                if data == 0 :break
                title_list.append(good.name)
                data_list.append({'value':data,'name':good.name})
    else: # 即每日统计 DailyStatistics 中的数据 不支持 指定style
        if style and style not in {'line','bar'} : return HttpResponse('{"title_list":[],"data_list":[]}')
        query_set = DailyStatistics.objects.all()
        if year: query_set=query_set.filter(date__year=int(year))
        if month: query_set=query_set.filter(date__month=int(month))
        if day: query_set=query_set.filter(date__day=int(day))
        # 转为json格式输出
        query_set = list(map(lambda x:json.loads(str(x)),list(query_set)))
        query_set.sort(key=lambda x:x['date']) # 按日期从小到大
        print(query_set)
        title_list = [record['date'] for record in query_set ]
        data_list = [record[field] for record in query_set ]
        # 是否为累计模式
        if type_ and type_ == 'add':
            data_list = [sum(data_list[:i+1]) for i in range(len(data_list))]
    return HttpResponse(json.dumps({"title_list":title_list,"data_list":data_list}))

# 支付宝SDK入口：https://github.com/fzlee/alipay/blob/master/README.zh-hans.md
class CreateOrder(View):
    """
    创建定单
    """
    def post(self, request):
        cookie = request.COOKIES
        goods_type = request.POST.get('goods_type',None)
        category = request.POST.get('category',None)
        login = cookie.get('login',None)
        phone = cookie.get('phone',None)
        if not login : return redirect('/static/login.html')
        if User.objects.filter(phone=phone):
            user = User.objects.get(phone=phone)
        order_id = "x2" + str(time.time()).replace('.','')
        PRICE_MAP ={
            'trend_history':{'10':'29.8','11':'54','12':'79','13':'140','14':'255',
            '15':'399','16':'1080','17':'2000'}
        }
        price  = PRICE_MAP[goods_type].get(category)
        print('price=',price)
        # OrderInfo.objects.filter(user=user,status='UNPAID')
        OrderInfo.objects.create(order_id=order_id,user=user,total_amount=price,status='UNPAID')
        return JsonResponse({'code': 0, 'errmsg': 'ok','order_id':order_id})
        # return redirect('/payment/')
        
class PayUrlView( View):

    def post(self, request):
        cookie = request.COOKIES
        order_id = request.POST.get('order_id',None)
        login = cookie.get('login',None)
        phone = cookie.get('phone',None)
        subject = request.POST.get('subject',None)
        return_url = request.POST.get('return_url',None)
        if not login : return redirect('/static/login.html')
        # 1. 获取订单id
        # 2. 验证订单id (根据订单id查询订单信息)
        try:
            # 为了业务逻辑的准确性,
            # 查询待支付的订单
            order = OrderInfo.objects.get(order_id=order_id,
                                          status='UNPAID')
        except OrderInfo.DoesNotExist:
            return JsonResponse({'code': 400, 'errmsg': '没有此订单'})
        # 3. 读取应用私钥和支付宝公钥
        app_private_key_string = open(settings.APP_PRIVATE_KEY_PATH).read()
        alipay_public_key_string = open(settings.ALIPAY_PUBLIC_KEY_PATH).read()
        # 4. 创建支付宝实例
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_string=app_private_key_string,
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_string=alipay_public_key_string,
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=False,   # 默认False
            verbose=True,  # 输出调试数据
            config=AliPayConfig(timeout=15)  # 可选, 请求超时时间
        )
        # 5. 调用支付宝的支付方法
        subject = subject or "Price比价平台测试订单"

        # https://openapi.alipay.com/gateway.do 这个是线上的
        # 'https://openapi.alipaydev.com/gateway.do' 这个是沙箱的
        order_string = alipay.api_alipay_trade_page_pay(
            out_trade_no=order_id,
            total_amount=str(order.total_amount),  # 一定要进行类型转换,因为decimal不是基本数据类型
            subject=subject,
            return_url=return_url,  # 支付成功之后,跳转的页面
            notify_url="https://127.0.0.1:8000/notify"  # 可选, 不填则使用默认notify url
        )
        # 6.  拼接连接
        pay_url = 'https://openapi.alipaydev.com/gateway.do?' + order_string
        # 7. 返回响应
        return JsonResponse({'code': 0, 'errmsg': 'ok', 'alipay_url': pay_url})


class PaymentStatusView(View):

    def put(self, request):
        # 1. 接收数据
        data = request.GET
        # 2. 查询字符串转换为字典 验证数据
        data = data.dict()

        # 3. 验证没有问题获取支付宝交易流水号
        signature = data.pop("sign")

        app_private_key_string = open(settings.APP_PRIVATE_KEY_PATH).read()
        alipay_public_key_string = open(settings.ALIPAY_PUBLIC_KEY_PATH).read()
        # 创建支付宝实例
        alipay = AliPay(
            appid=settings.ALIPAY_APPID,
            app_notify_url=None,  # 默认回调url
            app_private_key_string=app_private_key_string,
            # 支付宝的公钥，验证支付宝回传消息使用，不是你自己的公钥,
            alipay_public_key_string=alipay_public_key_string,
            sign_type="RSA2",  # RSA 或者 RSA2
            debug=settings.ALIPAY_DEBUG,  # 默认False
            config=AliPayConfig(timeout=15)  # 可选, 请求超时时间
        )
        success = alipay.verify(data, signature)
        if success:
            # 获取 trade_no	String	必填	64	支付宝交易号
            trade_no = data.get('trade_no')
            order_id = data.get('out_trade_no')
            Payment.objects.create(
                trade_id=trade_no,
                order_id=order_id
            )
            # 4. 改变订单状态

            OrderInfo.objects.filter(order_id=order_id).update(status='UNSEND')

            return JsonResponse({'code': 0, 'errmsg': 'ok', 'trade_id': trade_no})
        else:
            return JsonResponse({'code': 400, 'errmsg': '请到个人中心的订单中查询订单状态'})